package com.xuan.xseq.seq.impl;

import com.xuan.xseq.exception.SequenceException;
import com.xuan.xseq.range.SeqRange;
import com.xuan.xseq.range.SeqRangeMgr;
import com.xuan.xseq.seq.Sequence;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 获取序列号通用接口默认实现
 * Created by xuan on 2018/1/10.
 */
public class DefaultSequence implements Sequence {

    private final Lock lock = new ReentrantLock();

    private SeqRangeMgr seqRangeMgr;

    private volatile SeqRange currentRange;

    private String name;

    @Override
    public long nextValue() throws SequenceException {
        if (null == currentRange) {
            lock.lock();
            try {
                if (null == currentRange) {
                    currentRange = seqRangeMgr.nextRange(name);
                }
            } finally {
                lock.unlock();
            }
        }

        long value = currentRange.getAndIncrement();
        if (value == -1) {
            lock.lock();
            try {
                for (; ; ) {
                    if (currentRange.isOver()) {
                        currentRange = seqRangeMgr.nextRange(name);
                    }

                    value = currentRange.getAndIncrement();
                    if (value == -1) {
                        continue;
                    }

                    break;
                }
            } finally {
                lock.unlock();
            }
        }

        if (value < 0) {
            throw new SequenceException("Sequence value overflow, value = " + value);
        }

        return value;
    }

    @Override
    public void setSeqRangeMgr(SeqRangeMgr seqRangeMgr) {
        this.seqRangeMgr = seqRangeMgr;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

}
